// Written by Marco, modified by Flame
Class FBot extends KFInvasionBot;

var float NextTargetCheck,NextKnifeTime,NextWeaponSwitch;
var class<KFWeapon> FaveWeapon;
var byte HealState,OldMovesCount;
var float RetreatTime;
var NavigationPoint CurrentMov,OldMoves[4];
var MP7MMedicGun MyMedGun;
var FBot BeggingTarget,AnswerBegger;
var PlayerController DonatePlayer,AssistingPlayer;

var bool bHasWeapon;

function SetCombatTimer()
{
	SetTimer(0.16f, True);
}

final function SetFaveGun() // Pick weapon of choise from trader.
{
	local byte Index;
	local KFLevelRules L;
	local int i;
	local array< class<Pickup> > Choises;

	L = KFGameType(Level.Game).KFLRules;
	if( KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill==None || L==None )
		return;
	Index = KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.Default.PerkIndex;

	for( i=0; i<ArrayCount(L.ItemForSale); ++i )
		if( Class<KFWeaponPickup>(L.ItemForSale[i])!=None && Index==Class<KFWeaponPickup>(L.ItemForSale[i]).Default.CorrespondingPerkIndex )
			Choises[Choises.Length] = L.ItemForSale[i];
	if( Choises.Length>0 )
		FaveWeapon = class<KFWeapon>(Choises[Rand(Choises.Length)].Default.InventoryType);
}

function float AdjustDesireFor(Pickup P)
{
	if( FaveWeapon!=None && FaveWeapon==P.InventoryType )
		return 10.f;
	if( KFWeaponPickup(P)!=None && !WeaponIsForPerk(Class<KFWeaponPickup>(P.Class)) )
		return -1000.f;
	return Super.AdjustDesireFor(P);
}

final function bool WeaponIsForPerk( class<KFWeaponPickup> Wep )
{
	return (Wep.Default.CorrespondingPerkIndex==KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.Default.PerkIndex);
}

function bool ShouldGoShopping()
{
	// Can't shop if the shop ain't open
/* 	if( KFGameType(Level.Game).bWaveInProgress )
		return false;

	// Don't need to shop if we've just shopped
	if( LastShopTime>level.TimeSeconds )
		return false;

	if( !bHasChecked && FRand()<0.1 )
	{
		LastShopTime = level.TimeSeconds+FRand()*120;
		bHasChecked = True;
		Return False;
	}

	// At the end of the day, it's all about having money, really
	return (PlayerReplicationInfo.score>=100); */
	return false;
}

final function bool ShouldBegForCash()
{
	local Controller C;
	local array<PlayerController> PC;
	local byte i;

	if( KFGameType(Level.Game).bWaveInProgress || AnswerBegger!=None )
		return false;

	if( PlayerReplicationInfo.Score<300 )
	{
		for( C=Level.ControllerList; C!=None; C=C.nextController )
			if( FBot(C)!=None && FBot(C).AnswerBeg(Pawn) && ActorReachable(C.Pawn) )
			{
				BeggingTarget = FBot(C);
				BeggingTarget.AnswerBegger = Self;
				//SendMessage(None, 'SUPPORT', 2, 0.5f, ''); // I need some money!
				GoToState('BeggingCash','Begin');
				return true;
			}
	}
	else if( PlayerReplicationInfo.Score>900 )
	{
		for( C=Level.ControllerList; C!=None; C=C.nextController )
			if( PlayerController(C)!=None && KFPawn(C.Pawn)!=None && C.PlayerReplicationInfo.Score<200 && ActorReachable(C.Pawn) )
				PC[PC.Length] = PlayerController(C);

		while( PC.Length>0 )
		{
			i = Rand(PC.Length);
			DonatePlayer = PC[i];
			PC.Remove(i,1);
			for( C=Level.ControllerList; C!=None; C=C.nextController )
				if( C!=Self && FBot(C)!=None && FBot(C).DonatePlayer==DonatePlayer )
				{
					DonatePlayer = None;
					break;
				}
			if( DonatePlayer!=None )
			{
				//SendMessage(None, 'ALERT', 2, 0.25f, '');
				GoToState('GivePoorPlayerCash','Begin');
				return true;
			}
		}
	}
	return false;
}

final function bool AnswerBeg( Pawn Other )
{
	if( BeggingTarget!=None || AnswerBegger!=None || PlayerReplicationInfo.Score<800 || Pawn==None || VSize(Pawn.Location-Other.Location)>1000.f || Enemy!=None )
		return false;
	return true;
}

function AnswerBeggerNow()
{
	if( AnswerBegger==None || AnswerBegger.Pawn==None || !ActorReachable(AnswerBegger.Pawn) )
	{
		if( AnswerBegger!=None )
		{
			//SendMessage(None, 'ACK', 1, 1.5f, ''); // No!
			AnswerBegger = None;
		}
		return;
	}
	//SendMessage(None, 'ACK', 0, 1.5f, ''); // Ok!
	GoToState('RespondToBeg');
}

final function StartAssistPlayer( PlayerController Other )
{
	//SendMessage(Other.PlayerReplicationInfo, 'ACK', 0, 1.5f, ''); // Ok!
	AssistingPlayer = Other;
}
final function bool CanAffordX( class<Pickup> aItem, bool bIgnorePerk )
{
	local class<kfWeaponPickup> aWeapon;
	local Inventory InvIt;
	local KFWeapon Weap;
	local bool bFoundInInventory;

	aWeapon = class<KFWeaponPickup>(aItem);

	if( aWeapon!=none && (bIgnorePerk || WeaponIsForPerk(aWeapon)) )
	{
		bFoundInInventory=false;
		for(InvIt=Pawn.Inventory; InvIt!=none; InvIt=InvIt.Inventory)
		{
			Weap = KFWeapon(InvIt);
			if(Weap!=none)
			{
				bFoundInInventory=true;
				if(Weap.AmmoClass[0]!=none && Weap.Class==aWeapon.default.InventoryType)
				{
					if( PlayerReplicationInfo.score>aWeapon.default.ammocost )
						return true;
				}
			}
		}

		// if we didn't find it above, we need to see if we can buy the whole gun, not just ammo
		if(!bFoundInInventory && (aWeapon.default.Cost*GetVet().Static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo),aWeapon))<PlayerReplicationInfo.Score
		&& aWeapon.default.weight < (KFHumanPawn(pawn).MaxCarryWeight - KFHumanPawn(pawn).CurrentWeight) )
			return true;
	}
	return false;
}
final function class<KFVeterancyTypes> GetVet()
{
	return KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill;
}
final function bool TryToBuyFav() // Try to buy favorite weapon.
{
	local Inventory I,NI;
	local int CollectedCash,Price;
	local KFWeapon W;

	Price = class<KFWeaponPickup>(FaveWeapon.Default.PickupClass).default.Cost*GetVet().Static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo),FaveWeapon.Default.PickupClass);
	CollectedCash = int(PlayerReplicationInfo.Score);

	// If too expensive, sell out stuff until can get it.
	if( Price>CollectedCash )
	{
		for( I=Pawn.Inventory; I!=none; I=I.Inventory )
		{
			W = KFWeapon(I);
			if( W!=None && !W.bKFNeverThrow )
				CollectedCash+=GetWeaponWorth(W);
		}
		if( Price>CollectedCash )
			return false;
		for( I=Pawn.Inventory; I!=none; I=NI )
		{
			NI = I.Inventory;
			if( SellWeapon(KFWeapon(I)) && Price<=PlayerReplicationInfo.Score )
				break;
		}
	}

	Price = FaveWeapon.default.Weight;
	CollectedCash = (KFHumanPawn(pawn).MaxCarryWeight - KFHumanPawn(pawn).CurrentWeight);

	// If too heavy, sell out stuff until can get it.
	if( Price>CollectedCash )
	{
		for( I=Pawn.Inventory; I!=none; I=I.Inventory )
		{
			W = KFWeapon(I);
			if( W!=None && !W.bKFNeverThrow )
				CollectedCash+=W.Weight;
		}
		if( Price>CollectedCash )
			return false; // Wierd...
		for( I=Pawn.Inventory; I!=none; I=NI )
		{
			NI = I.Inventory;
			if( SellWeapon(KFWeapon(I)) && Price<=(KFHumanPawn(pawn).MaxCarryWeight - KFHumanPawn(pawn).CurrentWeight) )
				break;
		}
	}
	return true;
}
final function bool SellWeapon( KFWeapon W )
{
	if( W==None || W.bKFNeverThrow )
		return false;
	PlayerReplicationInfo.Score+=GetWeaponWorth(W);
	W.Destroy();
	return true;
}
final function int GetWeaponWorth( KFWeapon W )
{
	if( W.SellValue>0 )
		return W.SellValue;
	return class<KFWeaponPickup>(W.PickupClass).Default.Cost*0.75*GetVet().Static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo),W.PickupClass);
}
function array< class<Pickup> > GetLegalPurchases()
{
	local int i;
	local KFLevelRules KFLR;
	local array<class<Pickup> > RetList;

	if( FaveWeapon!=None && Pawn.FindInventoryType(FaveWeapon)==None && TryToBuyFav() )
		RetList[RetList.Length] = FaveWeapon.Default.PickupClass;
	else
	{
		KFLR = KFGameType(Level.game).KFLRules;
		for(i=0; i<KFLR.MAX_BUYITEMS; i++ )
		{
			if( CanAffordX(KFLR.ItemForSale[i],false) )
				RetList[RetList.Length] = KFLR.ItemForSale[i];
		}
	}
	return RetList;
}
final function BuyKevlar()
{
	local float Cost;
	local int UnitsAffordable;

	if ( UnrealPawn(Pawn).ShieldStrength>=100 )
		Return;

	Cost = class'Vest'.default.ItemCost * ((100.0 - UnrealPawn(Pawn).ShieldStrength) / 100.0);
	Cost *= GetVet().static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), class'Vest');

	if ( PlayerReplicationInfo.Score >= Cost )
	{
		PlayerReplicationInfo.Score -= Cost;
		UnrealPawn(Pawn).ShieldStrength = 100;
	}
	else if ( UnrealPawn(Pawn).ShieldStrength>0 )
	{
		Cost = class'Vest'.default.ItemCost/100.f;
		Cost *= GetVet().static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), class'Vest');

		UnitsAffordable = int(PlayerReplicationInfo.Score / Cost);
		PlayerReplicationInfo.Score -= int(Cost * UnitsAffordable);
		UnrealPawn(Pawn).ShieldStrength += UnitsAffordable;
	}
	PlayerReplicationInfo.Score = int(PlayerReplicationInfo.Score);
}
function DoTrading()
{
	local KFWeapon Weap;
	local int i;
	local class<KFWeaponPickup> BuyWeapClass;
	local int NumCanAfford, NumNeeded, NumToBuy;
	local array<class<Pickup> > ShoppingList;
	local int OldCash,Cost;
	local byte LCount;

	LastShopTime = level.TimeSeconds+30+500*FRand();

	OldCash = PlayerReplicationInfo.score + 1;

	while ( (PlayerReplicationInfo.score > 20) && PlayerReplicationInfo.score!=OldCash && LCount++<10 )
	{
		OldCash = PlayerReplicationInfo.score;

		ShoppingList = GetLegalPurchases();
		if( ShoppingList.Length==0 )
			Break;

		// kludge to stack the odds to the low numbers where the best kit is ;)
		if( FaveWeapon!=None && FaveWeapon==ShoppingList[0] )
			i = 0; // Wants to get favorite weapon first!
		else if(ShoppingList.length < 3 || frand() < 0.5)
			i = rand(ShoppingList.length);
		else i = rand(0.5*ShoppingList.length);

		BuyWeapClass = class<KFWeaponPickup>(ShoppingList[i]);
		if( BuyWeapClass==None )
			Continue;
		Weap = FindWeaponInInv(BuyWeapClass);

		if(Weap!=none) // already own gun, buy ammo
		{
			Cost = BuyWeapClass.default.ammocost*GetVet().Static.GetAmmoCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo),BuyWeapClass);
			NumCanAfford = PlayerReplicationInfo.score / Cost;
			NumNeeded = (Weap.AmmoClass[0].default.MaxAmmo-Weap.AmmoCharge[0]) / Weap.MagCapacity;
			NumToBuy = Min(NumCanAfford, NumNeeded);
			PlayerReplicationInfo.score -= Cost*NumToBuy;
			Weap.AddAmmo(Weap.MagCapacity * NumToBuy, 0);
		}
		else // buy that gun
		{
			Cost = BuyWeapClass.default.ammocost*GetVet().Static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo),BuyWeapClass);
			Weap = KFWeapon(Spawn(BuyWeapClass.default.InventoryType));
			if( Weap!=None )
				Weap.GiveTo(pawn);
			PlayerReplicationInfo.Score -= Cost;
		}
	}
	if( PlayerReplicationInfo.Score>0 ) // Also purchase armor.
		BuyKevlar();
	SwitchToBestWeapon();
}
function bool GetNearestShop()
{
	local KFGameType KFGT;
	local int i,l;
	local float Dist,BDist;
	local ShopVolume Sp;

	KFGT = KFGameType(Level.Game);
	if( KFGT==None )
		return false;
	l = KFGT.ShopList.Length;
	for( i=0; i<l; i++ )
	{
		if( !KFGT.ShopList[i].bCurrentlyOpen )
			continue;
		if( !KFGT.ShopList[i].bTelsInit )
			KFGT.ShopList[i].InitTeleports();
		Dist = VSize(KFGT.ShopList[i].Location-Pawn.Location);
		if( Dist<BDist || Sp==None )
		{
			Sp = KFGT.ShopList[i];
			BDist = Dist;
		}
	}
	if( Sp==None )
		return false;
	if( Sp.BotPoint==None )
	{
		Sp.BotPoint = FindShopPoint(Sp);
		if( Sp.BotPoint==None )
			return false;
	}
	ShoppingPath = Sp.BotPoint;
/* 	if( Mut.NextTraderMsg<Level.TimeSeconds )
	{
		SendMessage(None, 'DIRECTION', 0, 15, 'TEAM'); // Get to the Trader
		Mut.NextTraderMsg = Level.TimeSeconds+30.f;
	} */
	return true;
}
final function NavigationPoint FindShopPoint( ShopVolume S )
{
	local NavigationPoint N,BN;
	local float Dist,BDist;

	for( N=Level.NavigationPointList; N!=None; N=N.nextNavigationPoint )
	{
		Dist = VSizeSquared(N.Location-S.Location);
		if( BN==None || BDist>Dist )
		{
			BN = N;
			BDist = Dist;
		}
	}
	return BN;
}
function bool EnemyReallyScary()
{
	local Controller C;
	local KFMonster M;
	local byte i;

	for( C=Level.ControllerList; C!=None; C=C.nextController )
	{
		M = KFMonster(C.Pawn);
		if( M==None || M.Health<=0 )
			continue;
		if( M.IsA('ZombieSiren') )
		{
			if( VSize(M.Location-Pawn.Location)<500.f ) // Fear sirens in scream distance
				return true;
		}
		else if( M.IsA('ZombieScrake') )
		{
			if( VSize(M.Location-Pawn.Location)<200.f ) // Fear scrakes in close distance
				return true;
		}
		else if( M.IsA('ZombieFleshPound') )
		{
			if( C.Enemy==Pawn && VSize(M.Location-Pawn.Location)<1000.f ) // Fear fleshpounds targeting in me.
				return true;
		}
		if( VSize(M.Location-Pawn.Location)<150.f )
		{
			if( Pawn.Health<=20 )
				return true; // Fear all close distance enemies when low on health.
			else if( ++i>3 )
				return true; // Fear group of zeds at close distance
		}
	}
	return false;
}
final function float GetEnemyDesire( KFMonster M, bool bCheckedSight )
{
	local float Cost;

	Cost = VSize(M.Location-Pawn.Location);
	if( Cost<100 )
		Cost*=0.5f; // Close range, much bigger threat.
	Cost*=(1.f/FMax(float(M.ScoringValue)*0.001f,0.7f));
	if( M.Health<50 )
		Cost*=0.75f; // Weaklings...
	if( Enemy==M )
		Cost*=0.85f;
	if( !bCheckedSight && !LineOfSightTo(M) )
		Cost*=2.f;
	if( M.Controller!=None && M.Controller.Enemy==Self )
		Cost*=0.85f;
	return Cost;
}
function FindBetterTarget()
{
	local Controller C;
	local KFMonster P,BP;
	local float Cost,Best;

	for( C=Level.ControllerList; C!=None; C=C.nextController )
	{
		P = KFMonster(C.Pawn);
		if( P==None || P.Health<=0 || !LineOfSightTo(P) || P.bDecapitated )
			continue;
		Cost = GetEnemyDesire(P,true);
		if( BP==None || Best>Cost )
		{
			BP = P;
			Best = Cost;
		}
	}
	if( BP!=None && BP!=Enemy )
	{
		Enemy = BP;
		Target = BP;
	}
}

final function bool TryToHealSelf()
{
	local Syringe S;
	local Inventory I;
	local byte C;

	for( I=Pawn.Inventory; (I!=None && C++<250); I=I.Inventory )
	{
		S = Syringe(I);
		if( S!=None )
			break;
	}
	if ( S==none || S.ChargeBar() < 0.99f )
		return false;

	GoToState('GoHealSelf');
	return true;
}
function FightEnemy(bool bCanCharge, float EnemyStrength)
{
	local float enemyDist;
	local float AdjustedCombatStyle;
	local bool bFarAway, bOldForcedCharge;

	if( NextTargetCheck<Level.TimeSeconds )
	{
		FindBetterTarget();	
		NextTargetCheck = Level.TimeSeconds+1.f;
	}

	if ( (Squad == None) || (Enemy == None) || (Pawn == None) )
		log("HERE 3 Squad "$Squad$" Enemy "$Enemy$" pawn "$Pawn);

	if( Pawn.Health<75 && TryToHealSelf() && !ManyEnemiesAround(Pawn.Location) )
		return;
	if( EnemyReallyScary() )
	{
		GoalString = "Retreat";
		//if ( (PlayerReplicationInfo.Team != None) && (FRand() < 0.2) )
		//	SendMessage(None, 'ALERT', Rand(2)+1, 15, 'TEAM'); // RUN! - Wait for me!
		DoRetreat();
		return;
	}
	if ( (Enemy == FailedHuntEnemy) && (Level.TimeSeconds == FailedHuntTime) )
	{
		GoalString = "FAILED HUNT - HANG OUT";
		if ( EnemyVisible() )
			bCanCharge = false;
		else if ( FindInventoryGoal(0) )
		{
			SetAttractionState();
			return;
		}
		else
		{
			WanderOrCamp(true);
			return;
		}
	}
	bOldForcedCharge = bMustCharge;
	bMustCharge = false;
	enemyDist = VSize(Pawn.Location - Enemy.Location);
	if( Pawn.Weapon==None )
		AdjustedCombatStyle = CombatStyle;
	else AdjustedCombatStyle = CombatStyle + Pawn.Weapon.SuggestAttackStyle();
	Aggression = 1.5 * FRand() - 0.8 + 2 * AdjustedCombatStyle - 0.5 * EnemyStrength + FRand() * (Normal(Enemy.Velocity - Pawn.Velocity) Dot Normal(Enemy.Location - Pawn.Location));

	if ( enemyDist > MAXSTAKEOUTDIST )
		Aggression += 0.5;
	if ( (Pawn.Physics == PHYS_Walking) || (Pawn.Physics == PHYS_Falling) )
	{
		if (Pawn.Location.Z > Enemy.Location.Z + TACTICALHEIGHTADVANTAGE)
			Aggression = FMax(0.0, Aggression - 1.0 + AdjustedCombatStyle);
		else if ( (Skill < 4) && (enemyDist > 0.65 * MAXSTAKEOUTDIST) )
		{
			bFarAway = true;
			Aggression += 0.5;
		}
		else if (Pawn.Location.Z < Enemy.Location.Z - Pawn.CollisionHeight) // below enemy
			Aggression += CombatStyle;
	}

	// see enemy - decide whether to charge it or strafe around/stand and fire
	BlockedPath = None;
	Target = Enemy;

	if( (Pawn.Weapon!=None && Pawn.Weapon.bMeleeWeapon) || (bCanCharge && bOldForcedCharge) )
	{
		GoalString = "Charge";
		DoCharge();
		return;
	}
	if ( Pawn.Weapon!=None && !Pawn.Weapon.bMeleeWeapon )
	{
		GoalString = "Long Ranged Attack";
		DoRangedAttackOn(Enemy);
		return;
	}

	if ( bCanCharge && (Skill < 5) && bFarAway && (Aggression > 1) && (FRand() < 0.5) )
	{
		GoalString = "Charge closer";
		DoCharge();
		return;
	}

	if ( (Pawn.Weapon!=None && Pawn.Weapon.RecommendRangedAttack()) || IsSniping() || ((FRand() > 0.17 * (skill + Tactics - 1)) && !DefendMelee(enemyDist)) )
	{
		GoalString = "Ranged Attack";
		DoRangedAttackOn(Enemy);
		return;
	}

	if ( bCanCharge )
	{
		if ( Aggression > 1 )
		{
			GoalString = "Charge 2";
			DoCharge();
			return;
		}
	}

	if( Pawn.Health<=25 && VSize(Pawn.Location - Enemy.Location)<120 )
	{
		GoalString = "Retreat";
		DoRetreat();
		GotoState('FallBack');
	}

	GoalString = "Do tactical move";
	DoTacticalMove();
}
function YellAt(Pawn Moron)
{
/* 	if ( (Enemy != None) || (Mut.NextYellTime>Level.TimeSeconds) || (FRand() < 0.7) )
		return;

	Mut.NextYellTime = Level.TimeSeconds+5.f+3.f*FRand(); */
	//SendMessage(None, 'INSULT', 1, 5, ''); // Insult Players
}
function NotifyKilled(Controller Killer, Controller Killed, pawn KilledPawn)
{
/* 	if( Killer==Self && Mut.NextYellTime<Level.TimeSeconds && FRand()<0.4 )
	{
		//SendMessage(None, 'INSULT', 0, 5, ''); // Insult Specimen
		Mut.NextYellTime = Level.TimeSeconds+10.f+10.f*FRand();
	} */
	Super.NotifyKilled(Killer,Killed,KilledPawn);
}

function SendMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait, name BroadcastType)
{
	if( MessageType=='INSULT' || MessageType=='DIRECTION' || MessageType=='ALERT' || MessageType=='SUPPORT' || MessageType=='ACK' || MessageType=='AUTO' )
	{
		// limit frequency of same message
		if ( (MessageType == OldMessageType) && (MessageID == OldMessageID)
			&& (Level.TimeSeconds - OldMessageTime < Wait) )
			return;

		if ( Level.Game.bGameEnded || Level.Game.bWaitingToStartMatch )
			return;

		OldMessageID = MessageID;
		OldMessageType = MessageType;

		//Flame
		//if (Pawn != none)
		//	SendVoiceMessage(PlayerReplicationInfo, Recipient, MessageType, MessageID, BroadcastType, Pawn, Pawn.Location);
		//else SendVoiceMessage(PlayerReplicationInfo, Recipient, MessageType, MessageID, BroadcastType, None, Location);
	}
}
exec function SwitchToBestWeapon()
{
	local float rating,Best,EnemyDist;
	local Inventory I;
	local Weapon BestW;

	if ( Pawn == None || Pawn.Inventory == None || (Pawn.PendingWeapon!=None && Pawn.Weapon!=None) || (NextWeaponSwitch>Level.TimeSeconds && Knife(Pawn.Weapon)==None) )
		return;

	if( Enemy!=None )
		EnemyDist = VSize(Enemy.Location-Pawn.Location);
	for( I=Pawn.Inventory; I!=None; I=I.Inventory )
	{
		if( KFWeapon(I)==None )
			continue;
		rating = GetWeaponRating(KFWeapon(I),EnemyDist);
		if( FaveWeapon!=None && FaveWeapon==I.Class && rating>0 )
			rating*=1.2f;
		if( BestW==None || Best<rating )
		{
			BestW = Weapon(I);
			Best = rating;
		}
	}
	if( Pawn.Weapon==BestW || BestW==None )
		return;
	NextWeaponSwitch = Level.TimeSeconds+2.f;
	Pawn.PendingWeapon = BestW;
	StopFiring();
	if( Knife(Pawn.Weapon)!=None )
		NextKnifeTime = Level.TimeSeconds+2.f+FRand()*6.f;
	if ( Pawn.Weapon==None )
		Pawn.ChangedWeapon();
	else if( !Pawn.Weapon.HasAmmo() ) // Most likely weapon is stuck here.
	{
		Pawn.Weapon.PutDown();
		Pawn.Weapon.ClientState = WS_PutDown;
		Pawn.Weapon.Timer();
	}
	else Pawn.Weapon.PutDown();
}
final function float GetWeaponRating( KFWeapon Wep, float Dist )
{
	if( !Wep.HasAmmo() || (Enemy!=None && !Wep.CanAttack(Enemy)) )
		return -2;
	switch( Wep.Class )
	{
	case Class'Syringe':
	case Class'SyringeW':
	case Class'Frag':
	case Class'FragW':
	case Class'Welder':
	case Class'WelderW':
	case Class'SWelderW':
		return -1.f;
	case Class'Single':
		return 3.f;
	case Class'SingleW':
		return 3.f;
	case Class'MK23W':
		return 3.f;
	case Class'Knife':
		if( Dist<100.f )	return 3.f;
		return 2.f;
	case Class'AA12W':
		if( Dist<800.f )	return 14.f;
		return 3.f;
	case Class'AFS12W':
		if( Dist<800.f )	return 15.f;
		return 4.f;
	case Class'SBoomStickW': 
		if( Dist<500.f )	return 16.f;
		return 5.f;
	case Class'KatanaW':
		if( Enemy==None )
			return 100.f;
		if( Dist<100.f )
			return 100.f;
		if( Dist<400.f )
			return 10.f;
		return 3.f;
	case Class'FireAxeW':
		if( Enemy==None )
			return 100.f;
		if( Dist<100.f )
			return 101.f;
		if( Dist<400.f )
			return 11.f;
		return 4.f;
	case Class'ChainsawW':
		if( Dist<100.f )
			return 102.f;
		if( Dist<400.f )
			return 12.f;
		return 5.f;
	case Class'ThompsonSubmachineGun':
		if( Dist<1200.f )
			return 10.f;
		return 3.f;
	case Class'M249':
		if( Dist<800.f )
			return 11.f;
		return 4.f;
	case Class'M249Ex':
		if( Dist<700.f )
			return 12.f;
		return 5.f;
	case Class'FlameThrower':
		if( Dist<600.f )
			return 10.f;
		return 3.f;
	case Class'M79FlameW':
		if( Dist>300.f )
			return 11.f;
		return 4.f;
	case Class'BomberW':
		if( Dist<600.f )
			return 12.f;
		return 5.f;
	case Class'DualDeagleW':
		if( Dist<500.f )
			return 10.f;
		return 3.f;
	case Class'M14W':
		if( Dist<600.f )
			return 11.f;
		return 4.f;
	case Class'M99W':
		if( Dist<1000.f )
			return 12.f;
		return 5.f;
	case Class'M79W':
		if( Dist>600.f )
			return 11.f;
		return 3.f;
	case Class'M32ClusterBombW':
		if( Dist>600.f )
			return 12.f;
		return 4.f;
	case Class'LAWW':
		if( Dist>600.f )
			return 13.f;
		return 5.f;
	case Class'AK47SHAssaultRifle':
		if( Dist<700.f )
			return 10.f;
		return 3.f;
	case Class'PKM':
		if( Dist<600.f )
			return 11.f;
		return 4.f;
	case Class'MAC10W':
		if( Dist<600.f )
			return 10.f;
		return 3.f;
	case Class'M7A3MW':
		if( Dist<600.f )
			return 10.f;
		return 3.f;
	case Class'CrossbowW':
		if( Dist>100.f )
			return 10.f;
		return 3.f;
	case Class'HuntingRifleW':
		if( Dist>100.f )
			return 11.f;
		return 4.f;
	case Class'PatGun':
		//Log("PatGun Prior");
		return 400.f;
	default:
		return 1.f;
	}
}
function rotator AdjustAim(FireProperties FiredAmmunition, vector projStart, int aimerror)
{
	local KFMonster M;
	local bool bAltMode;
	local vector HeadLoc;
	local Coords C;

	M = KFMonster(Enemy);
	if( FiredAmmunition.bInstantHit && M!=None && (Target==M || Target==None) && M.Mesh!=None )
	{
		if( Level.NetMode==NM_DedicatedServer && !M.bShotAnim )
		{
			if (M.Physics == PHYS_Falling)
				M.PlayAnim(M.AirAnims[0], 1.0, 0.0);
			else if( M.Physics == PHYS_Walking )
			{
				if( !M.IsAnimating(0) && !M.IsAnimating(1) )
				{
					if (M.bIsCrouched)
						M.PlayAnim(M.IdleCrouchAnim, 1.0, 0.0);
					else bAltMode = true;
					}
			}
			else if (M.Physics == PHYS_Swimming)
				M.PlayAnim(M.SwimAnims[0], 1.0, 0.0);
		}
		if( bAltMode )
			HeadLoc = M.Location + (M.OnlineHeadshotOffset >> M.Rotation);
		else
		{
			C = M.GetBoneCoords(M.HeadBone);
			HeadLoc = C.Origin + (M.HeadHeight * M.HeadScale * C.XAxis);
		}
		if( FastTrace(HeadLoc,projStart) )
			return rotator(HeadLoc-projStart);
	}
	return Super.AdjustAim(FiredAmmunition,projStart,aimerror);
}
function RemoveItemFromInv(Pawn P, string Item)
{
	local class<Weapon> WeaponClass;
	//local Weapon NewWeapon;
	local Inventory localInv;
//	local string ItemOnly;
//	local int PeriodLoc;
	
	WeaponClass = class<Weapon>(DynamicLoadObject(Item, class'Class'));

	localInv=P.FindInventoryType(WeaponClass);
	if( localInv == None )
		return;
	P.DeleteInventory(localInv);
	localInv.DropFrom(P.Location + VRand() * 16000);
}

function bool SetEnemy( Pawn NewEnemy )
{
	if( KFMonster(NewEnemy)==None || NewEnemy.Health<=0 || (Enemy!=None && GetEnemyDesire(KFMonster(Enemy),false)<GetEnemyDesire(KFMonster(NewEnemy),false)) )
		return false;
	Enemy = NewEnemy;
	EnemyChanged(LineOfSightTo(Enemy));
/* 	if( Mute.NextYellTime<Level.TimeSeconds && FRand()<0.1f )
	{
		SendMessage(None, 'INSULT', 0, 5, ''); // Insult Specimen
		Mute.NextYellTime = Level.TimeSeconds+20.f+20.f*FRand();
	} */
	return true;
}

function HearNoise(float Loudness, Actor NoiseMaker)
{
	if ( ((ChooseAttackCounter < 2) || (ChooseAttackTime != Level.TimeSeconds)) && NoiseMaker!=None && NoiseMaker.instigator!=None
	&& FastTrace(NoiseMaker.instigator.Location,Pawn.Location) && SetEnemy(NoiseMaker.instigator) )
		WhatToDoNext(2);
}
event SeePlayer(Pawn SeenPlayer)
{
	if ( ((ChooseAttackCounter < 2) || (ChooseAttackTime != Level.TimeSeconds)) && SetEnemy(SeenPlayer) )
		WhatToDoNext(3);
	if ( Enemy == SeenPlayer )
	{
		VisibleEnemy = Enemy;
		EnemyVisibilityTime = Level.TimeSeconds;
		bEnemyIsVisible = true;
	}
}
event bool NotifyBump(actor Other)
{
	local Pawn P;

	Disable('NotifyBump');
	P = Pawn(Other);
	if ( (P == None) || (P.Controller == None) || (Enemy == P) )
		return false;
	if ( SetEnemy(P) )
	{
		WhatToDoNext(4);
		return false;
	}

	if ( Enemy == P )
		return false;

	if ( CheckPathToGoalAround(P) )
		return false;

	if ( !AdjustAround(P) )
		CancelCampFor(P.Controller);
	return false;
}
function DamageAttitudeTo(Pawn Other, float Damage)
{
	if ( (Pawn.health > 0) && (Damage > 0) && SetEnemy(Other) )
		WhatToDoNext(5);
}

state GoHealSelf
{
Ignores SeePlayer,HearNoise,NotifyBump,FireWeaponAt;

	function BeginState()
	{
		StopFiring();
		HealState = 0;
		SetTimer(0.25f,true);
	}
	function Timer()
	{
		if( Syringe(Pawn.Weapon)==None )
		{
			Pawn.PendingWeapon = Weapon(Pawn.FindInventoryType(Class'Syringe'));
			if( Pawn.Weapon!=None )
				Pawn.Weapon.PutDown();
			else Pawn.ChangedWeapon();
			return;
		}
		if( HealState==0 )
		{
			Pawn.Weapon.StartFire(1);
			HealState++;
		}
		else
		{
			Global.SwitchToBestWeapon();
			WhatToDoNext(8);
		}
	}
	exec function SwitchToBestWeapon();
Begin:
	if( Enemy!=None )
		MoveTo(Normal(Pawn.Location-Enemy.Location)*400.f+VRand()*200.f+Pawn.Location);
	Pawn.Acceleration = vect(0,0,0);
}

function ExecuteWhatToDoNext()
{
	local float WeaponRating;

	SwitchToBestWeapon();
	bHasFired = false;
	GoalString = "WhatToDoNext at "$Level.TimeSeconds;
	if ( Pawn == None )
	{
		warn(GetHumanReadableName()$" WhatToDoNext with no pawn");
		return;
	}

	if ( Enemy == None )
	{
		if ( Level.Game.TooManyBots(self) )
		{
			if ( Pawn != None )
			{
				Pawn.Health = 0;
				Pawn.Died( self, class'Suicided', Pawn.Location );
			}
			Destroy();
			return;
		}
		if( Pawn.Health<=80 && TryToHealSelf() )
			return;
		BlockedPath = None;
		bFrustrated = false;
		if (Target == None || (Pawn(Target) != None && Pawn(Target).Health <= 0))
			StopFiring();
	}

	if ( ScriptingOverridesAI() && ShouldPerformScript() )
		return;
	if (Pawn.Physics == PHYS_None)
		Pawn.SetMovementPhysics();
	if ( (Pawn.Physics == PHYS_Falling) && DoWaitForLanding() )
		return;
	if ( (StartleActor != None) && !StartleActor.bDeleteMe && (VSize(StartleActor.Location - Pawn.Location) < StartleActor.CollisionRadius)  )
	{
		Startle(StartleActor);
		return;
	}
	bIgnoreEnemyChange = true;
	if ( /* (Enemy != None) && ((Enemy.Health <= 0) || (Enemy.Controller == None)) || */ !EnemyVisible() )
		LoseEnemy();

	bIgnoreEnemyChange = false;

	if( Enemy==None && ((ShouldGoShopping() && GoShopping()) || ShouldBegForCash()) )
		Return;
	else if( LastHealTime<Level.TimeSeconds && FindInjuredAlly() && !EnemyReallyScary() && GoHealing() )
		return;
	else if( Enemy==None && AssistingPlayer!=None )
		GoAssistPlayer();
	else
	{
		if ( AssignSquadResponsibility() )
		{
			if ( Pawn == None )
				return;
			SwitchToBestWeapon();
			return;
		}
		if ( ShouldPerformScript() )
			return;
		if ( Enemy != None )
			ChooseAttackMode();
		else
		{
			WeaponRating = Pawn.Weapon.CurrentRating/2000;

			if ( FindInventoryGoal(WeaponRating) )
			{
				if ( InventorySpot(RouteGoal) == None )
					GoalString = "fallback - inventory goal is not pickup but "$RouteGoal;
				else GoalString = "Fallback to better pickup "$InventorySpot(RouteGoal).markedItem$" hidden "$InventorySpot(RouteGoal).markedItem.bHidden;
				GotoState('FallBack');
			}
			else
			{
				// No enemy and no ammo to grab. Guess all there is left to do is to chill out
				GoalString = "WhatToDoNext Wander or Camp at "$Level.TimeSeconds;
				WanderOrCamp(true);
			}
		}
	}
}
function bool FindInjuredAlly()
{
	local controller c;
	local KFHumanPawn aKFHPawn;
	local float AllyDist;
	local float BestDist;
	local bool bGoMedGun;
	local vector Dummy;
	local Actor A;

	InjuredAlly = None;
	if( ManyEnemiesAround(Pawn.Location) )
		return false;
	if( FindMedGun() && MyMedGun.ChargeBar()>0.49f )
		bGoMedGun = true;
	else if( FindMySyringe()==none || MySyringe.ChargeBar()<0.6f )
		return false;

	for( c=level.ControllerList; c!=none; c=c.nextController )
	{
		if( C==Self )
			continue;

		aKFHPawn = KFHumanPawn(c.pawn);

		// If he's dead. dont bother.
		if( aKFHPawn==none || aKFHPawn.Health<=0 || aKFHPawn.Health>70 || VSizeSquared(aKFHPawn.Location-Pawn.Location)>1000000.f )
			continue;

		if( bGoMedGun )
		{
			A = Pawn.Trace(Dummy,Dummy,aKFHPawn.Location,Pawn.Location,true);
			if( A!=None && A!=aKFHPawn && A.Owner!=aKFHPawn )
				continue;
		}
		else if( !ActorReachable(aKFHPawn) )
			continue;
		AllyDist = VSizeSquared(Pawn.Location - aKFHPawn.Location);
		if( AKFHPawn.Health<40 )
			AllyDist*=0.5f;
		if( InjuredAlly==none || (AllyDist<BestDist) )
		{
			InjuredAlly = aKFHPawn;
			BestDist = AllyDist;
		}
	}
	if( !bGoMedGun && InjuredAlly!=None && ManyEnemiesAround(InjuredAlly.Location) )
		InjuredAlly = None;
	if( InjuredAlly!=None )
	{
		if( FBot(InjuredAlly.Controller)!=None )
			FBot(InjuredAlly.Controller).SendMessage(None, 'SUPPORT', Rand(2), 4.f, '');
		return true;
	}
	return false;
}
final function bool ManyEnemiesAround( vector Point )
{
	local Controller C;
	local byte i;

	for( C=Level.ControllerList; C!=None; C=C.nextController )
	{
		if( KFMonster(C.Pawn)!=None && KFMonster(C.Pawn).Health>0 && VSizeSquared(C.Pawn.Location-Point)<640000.f && FastTrace(Point,C.Pawn.Location) && ++i==5 )
			return true;
	}
	return false;
}
function DoRetreat()
{
	GotoState('Retreating');
}

function bool CanDoHeal()
{
	return (FindMySyringe()!=none && MySyringe.GetFireMode(0).AllowFire() && InjuredAlly!=none && InjuredAlly.Health>0 && InjuredAlly.Health<85);
}
final function bool CanUseMedHeal()
{
	return (FindMedGun() && MyMedGun.GetFireMode(0).AllowFire() && MyMedGun.ChargeBar()>0.49f && InjuredAlly!=none && InjuredAlly.Health>0 && InjuredAlly.Health<85);
}
final function bool FindMedGun()
{
	if( MyMedGun!=none && MyMedGun.Owner==Pawn )
		return true;

	MyMedGun = None;
	for(inv=pawn.Inventory; inv!=none; inv=inv.Inventory)
	{
		MyMedGun = MP7MMedicGun(inv);
		if( MyMedGun!=none )
			return true;
	}
	return false;
}
function bool GoHealing()
{
	if( InjuredAlly!=none && LastHealTime<Level.TimeSeconds )
	{
		LastHealTime = Level.TimeSeconds+2.f;
		GoalString = "HEALING";
		if( CanUseMedHeal() )
			GotoState('MedGunHealing');
		else GotoState('Healing');
		return true;
	}
	else return false;
}
function TimedFireWeaponAtEnemy()
{
	if ( Enemy != None )
		FireWeaponAt(Enemy);
	SetTimer(0.15f, True);
}
final function TossCash( int Amount, vector TossDir )
{
	local CashPickup CashPickup;

	PlayerReplicationInfo.Score = int(PlayerReplicationInfo.Score); // To fix issue with throwing 0 pounds.
	if( PlayerReplicationInfo.Score<=0 || Amount<=0 )
		return;
	Amount = Min(Amount,int(PlayerReplicationInfo.Score));

	TossDir = Normal(TossDir-Pawn.Location)*500.f + Vect(0,0,200);
	CashPickup = Spawn(class'CashPickup',,, Pawn.Location + Pawn.CollisionRadius * vector(Pawn.Rotation));

	if(CashPickup != none)
	{
		CashPickup.CashAmount = Amount;
		CashPickup.bDroppedCash = true;
		CashPickup.RespawnTime = 0;   // Dropped cash doesnt respawn. For obvious reasons.
		CashPickup.Velocity = TossDir;
		CashPickup.DroppedBy = Self;
		CashPickup.InitDroppedPickupFor(None);
		PlayerReplicationInfo.Score -= Amount;

		SendMessage(None, 'AUTO', 4, KFPawn(Pawn).DropCashMessageDelay, ''); // Loads of money!
	}
}

state Retreating
{
Ignores EnemyNotVisible,NotifyBump;

	function BeginState()
	{
		Pawn.bWantsToCrouch = false;
		SetTimer(0.1,true);
	}
	function Timer()
	{
		SetTimer(0.1,true);
		if( Enemy!=None )
		{
			Target = Enemy;
			FireWeaponAt(Enemy);
		}
	}
	final function PickNextRetMove()
	{
		local NavigationPoint N;
		local float Dist,BestDist;
		local byte i;
		local vector EnemyDir;

		if( CurrentMov==None )
		{
			for( N=Level.NavigationPointList; N!=None; N=N.nextNavigationPoint )
			{
				Dist = VSizeSquared(N.Location-Pawn.Location);
				if( Dist<10000.f )
				{
					CurrentMov = N;
					GoTo'MoveFound';
				}
				else if( CurrentMov==None || Dist<BestDist )
				{
					CurrentMov = N;
					BestDist = Dist;
				}
			}
			if( CurrentMov==None || !ActorReachable(CurrentMov) )
				return;
			MoveTarget = CurrentMov;
			return;
		}
		if( VSizeSquared(CurrentMov.Location-Pawn.Location)>10000.f )
		{
			if( ActorReachable(CurrentMov) )
			{
				MoveTarget = CurrentMov;
				return;
			}
			if( OldMovesCount>0 )
			{
				MoveTarget = OldMoves[0];
				CurrentMov = OldMoves[0];
			}
			else MoveTarget = None;
			return;
		}
		MoveFound:
		MoveTarget = None;
		EnemyDir = Normal(Enemy.Location-Pawn.Location);
		for( i=0; i<CurrentMov.PathList.Length; i++ )
		{
			N = CurrentMov.PathList[i].End;
			if( N==CurrentMov || !ActorReachable(N) )
				continue;
			Dist = (EnemyDir dot Normal(N.Location-Pawn.Location));
			if( SpecIsOldMove(N) )
				Dist+=0.2f;
			if( MoveTarget==None || Dist<BestDist )
			{
				MoveTarget = N;
				Dist = BestDist;
			}
		}
		if( MoveTarget!=None )
		{
			AddOldMove(CurrentMov);
			CurrentMov = NavigationPoint(MoveTarget);
		}
	}
	final function bool SpecIsOldMove( NavigationPoint N )
	{
		local byte i;

		for( i=0; i<OldMovesCount; i++ )
		{
			if( OldMoves[i]==N )
				return true;
		}
		return false;
	}
	final function AddOldMove( NavigationPoint N )
	{
		local byte i;

		if( OldMovesCount<ArrayCount(OldMoves) )
			OldMoves[OldMovesCount++] = N;
		else
		{
			for( i=1; i<ArrayCount(OldMoves); i++ )
				OldMoves[i-1] = OldMoves[i];
			OldMoves[ArrayCount(OldMoves)-1] = N;
		}
	}
	function ExecuteWhatToDoNext();
Begin:
	RetreatTime = Level.TimeSeconds+7.f+FRand()*15.f;
	CurrentMov = None;
	OldMovesCount = 0;
	while( RetreatTime>Level.TimeSeconds )
	{
		WaitForLanding();
Moving:
		if( Enemy==None )
		{
			MoveTo(VRand()*300.f+Pawn.Location,None);
			break;
		}
		PickNextRetMove();
		if( MoveTarget==None )
		{
			MoveTo(Normal(Pawn.Location-Enemy.Location)*400.f+VRand()*300.f+Pawn.Location,Enemy);
			break;
		}
		else MoveToward(MoveTarget,Enemy,GetDesiredOffset(),ShouldStrafeTo(MoveTarget));
	}
	Global.ExecuteWhatToDoNext();
	if ( bSoaking )
		SoakStop("STUCK IN RETREAT!");
	goalstring = goalstring$" STUCK IN RETREAT!";
}

state Healing
{
	function TimedFireWeaponAtEnemy()
	{
		if ( Pawn.Weapon==MySyringe  )
		{
			Target = InjuredAlly;
			FireWeaponAt(InjuredAlly);
			SetTimer(0.1, True);
		}
		else global.TimedFireWeaponAtEnemy();
	}
	final function SelectSyringe()
	{
		if( Pawn.Weapon==MySyringe )
			return;
		Pawn.PendingWeapon = MySyringe;
		if ( Pawn.Weapon==None )
			Pawn.ChangedWeapon();
		else if( !Pawn.Weapon.HasAmmo() ) // Most likely weapon is stuck here.
		{
			Pawn.Weapon.PutDown();
			Pawn.Weapon.ClientState = WS_PutDown;
			Pawn.Weapon.Timer();
		}
		else Pawn.Weapon.PutDown();
	}
Begin:
	SwitchToBestWeapon();
	WaitForLanding();
	if(MySyringe==none)
		FindMySyringe();

KeepMoving:
	SelectSyringe();

	if( !ActorReachable(InjuredAlly) )
	{
		MoveTarget = FindPathToward(InjuredAlly);

		if(MoveTarget!=none)
			MoveToward(MoveTarget,FaceActor(1),,false );
		else
		{
			LastHealTime = level.TimeSeconds+1;
			WhatToDoNext(151);
		}
	}
	else MoveToward(InjuredAlly,InjuredAlly,,false );

	if(InjuredAlly!=none)
	{
		MeLoc = pawn.Location;
		LockLoc = InjuredAlly.Location;
		LockerHeight = abs(MeLoc.Z - LockLoc.Z);
		MeLoc.Z = 0;
		LockLoc.Z = 0;
		LockerDist = VSize(MeLoc - LockLoc);

		// TODO - do we need to use TriggerHeight/2? Don't know, must check
		//        right now it'll prove the concept however
		if( LockerDist < MySyringe.weaponRange && LockerHeight < InjuredAlly.CollisionHeight )
		{
			if( !CanDoHeal() )
			{
				LastHealTime = level.TimeSeconds+2;
				WhatToDoNext(162);
			}
			else
			{
				sleep(0.5);
				goto('KeepMoving');
			}
		}
		else Goto('KeepMoving');
	}

	LastHealTime = level.TimeSeconds+2;
	WhatToDoNext(163);
	if ( bSoaking )
		SoakStop("STUCK IN HEALING!");
}
state MedGunHealing extends MoveToGoalWithEnemy
{
Ignores SwitchToBestWeapon;

	function bool WeaponFireAgain(float RefireRate, bool bFinishedFire)
	{
		if( Pawn.Weapon==MyMedGun )
		{
			if( NeedToTurn(InjuredAlly.Location) )
				return false;
			MyMedGun.StartFire(1);
			GoToState('MedGunHealing','FinishedMove');
			return true;
		}
		return Super.WeaponFireAgain(RefireRate,bFinishedFire);
	}
	function TimedFireWeaponAtEnemy()
	{
		if ( InjuredAlly!=None && Pawn.Weapon==MyMedGun )
		{
			Target = InjuredAlly;
			FireWeaponAt(InjuredAlly);
			SetTimer(0.1, True);
		}
		else global.TimedFireWeaponAtEnemy();
	}
	final function SelectMedGun()
	{
		if( Pawn.Weapon==MyMedGun )
			return;
		Pawn.PendingWeapon = MyMedGun;
		if ( Pawn.Weapon==None )
			Pawn.ChangedWeapon();
		else if( !Pawn.Weapon.HasAmmo() ) // Most likely weapon is stuck here.
		{
			Pawn.Weapon.PutDown();
			Pawn.Weapon.ClientState = WS_PutDown;
			Pawn.Weapon.Timer();
		}
		else Pawn.Weapon.PutDown();
	}
Begin:
	SelectMedGun();
	Pawn.Acceleration = vect(0,0,0);
	Focus = InjuredAlly;
	FinishRotation();
	Sleep(1.f);
FinishedMove:
	Sleep(0.25f);
	LastHealTime = level.TimeSeconds+2;
	WhatToDoNext(166);
}

State BeggingCash
{
Ignores SwitchToBestWeapon;

	function BeginState()
	{
		SetTimer(2,true);
	}
	function EndState()
	{
		if( PlayerReplicationInfo.Score>500 )
			SendMessage(None, 'ACK', 2, 1.5f, ''); // Thanks!
		if( BeggingTarget!=None )
		{
			BeggingTarget.AnswerBegger = None;
			BeggingTarget = None;
		}
		LastShopTime = -1;
	}
	function Timer()
	{
		if( BeggingTarget==None || BeggingTarget.Pawn==None || BeggingTarget.AnswerBegger!=Self )
		{
			EndState();
			WhatToDoNext(35);
			return;
		}
		BeggingTarget.AnswerBeggerNow();
	}
Begin:
	Pawn.Acceleration = vect(0,0,0);
	Focus = BeggingTarget.Pawn;
	Stop;
}
State RespondToBeg
{
Ignores AnswerBeggerNow;

	function BeginState()
	{
		SetTimer(0,false);
	}
	function EndState()
	{
		AnswerBegger = None;
	}
	final function vector GetMoveDest( Actor T )
	{
		local vector D;

		D = (T.Location-Pawn.Location);
		return Pawn.Location+Normal(D)*(VSize(D)-(Pawn.CollisionRadius+T.CollisionRadius+50.f));
	}
	function Timer()
	{
		if( AnswerBegger==None || AnswerBegger.Pawn==None || !CanSee(AnswerBegger.Pawn) || AnswerBegger.PlayerReplicationInfo.Score>600 )
			WhatToDoNext(38);
		else TossCash(50,AnswerBegger.Pawn.Location);
	}
Begin:
	MoveTo(GetMoveDest(AnswerBegger.Pawn),AnswerBegger.Pawn,false);
	Pawn.Acceleration = vect(0,0,0);
	Focus = AnswerBegger.Pawn;
	FinishRotation();
	SetTimer(0.2,true);
	Sleep(2.f);
	WhatToDoNext(39);
}
State GivePoorPlayerCash extends RespondToBeg
{
	function EndState()
	{
		DonatePlayer = None;
	}
	function Timer()
	{
		if( DonatePlayer==None || DonatePlayer.Pawn==None || !CanSee(DonatePlayer.Pawn) || DonatePlayer.PlayerReplicationInfo.Score>600 ||
			VSize(DonatePlayer.Pawn.Location-Pawn.Location)>250 )
			WhatToDoNext(38);
		else TossCash(50,DonatePlayer.Pawn.Location);
	}
Begin:
	MoveTo(GetMoveDest(DonatePlayer.Pawn),DonatePlayer.Pawn,false);
	Pawn.Acceleration = vect(0,0,0);
	Focus = DonatePlayer.Pawn;
	FinishRotation();
	SetTimer(0.2,true);
	Sleep(2.25f);
	WhatToDoNext(39);
}
function GoAssistPlayer()
{
	GoToState('AssistPlayer','Begin');
}
State AssistPlayer extends Roaming
{
	final function vector PickAssistOffset( Pawn Other )
	{
		local vector V;

		V.X = FRand()-0.5f;
		V.Y = FRand()-0.5f;
		return Other.Location+Normal(V)*(Other.CollisionRadius+Pawn.CollisionRadius+20+60*FRand());
	}
Begin:
	SwitchToBestWeapon();
	WaitForLanding();
	if( AssistingPlayer==None || AssistingPlayer.Pawn==None )
	{
		AssistingPlayer = None;
		WhatToDoNext(13);
	}
	if( VSize(AssistingPlayer.Pawn.Location-Pawn.Location)<150.f )
		GoTo'PausedMove';
	else if( ActorReachable(AssistingPlayer.Pawn) )
	{
		MoveTo(PickAssistOffset(AssistingPlayer.Pawn),None,false);
PausedMove:
		Focus = None;
		FocalPoint = Pawn.Location+VRand()*800.f;
		NearWall(MINVIEWDIST);
		Pawn.Acceleration = vect(0,0,0);
		Sleep(0.1+FRand());
	}
	else if( FindBestPathToward(AssistingPlayer.Pawn,true,true) )
		MoveToward(MoveTarget,FaceActor(1),GetDesiredOffset(),ShouldStrafeTo(MoveTarget));
	else AssistingPlayer = None;
	WhatToDoNext(13);
	if ( bSoaking )
		SoakStop("STUCK IN ROAMING!");
}

function AllWeaponsRemove(Pawn P)
{
	if ((P == None) || (Vehicle(P) != None) )
		return;
	RemoveItemFromInv(P,"PerksSimHostOrg.AFS12W");
	RemoveItemFromInv(P,"PerksSimHostOrg.BoomStickW");
	RemoveItemFromInv(P,"PerksSimHostOrg.KSGW");
	RemoveItemFromInv(P,"PerksSimHostOrg.Moss12W");
	RemoveItemFromInv(P,"PerksSimHostOrg.SBoomStickW");
	RemoveItemFromInv(P,"PerksSimHostOrg.ShotgunW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SShotgunW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SWelderW");
	RemoveItemFromInv(P,"PerksSimHostOrg.AA12W");
	RemoveItemFromInv(P,"PerksSimHostOrg.BenelliWShotgun");

	RemoveItemFromInv(P,"PerksSimHostOrg.ColtW");
	RemoveItemFromInv(P,"PerksSimHostOrg.CrossbowW");
	RemoveItemFromInv(P,"PerksSimHostOrg.DualDeagleW");
	RemoveItemFromInv(P,"PerksSimHostOrg.DeagleW");
	RemoveItemFromInv(P,"PerksSimHostOrg.DualMK23W");
	RemoveItemFromInv(P,"PerksSimHostOrg.MK23W");
	RemoveItemFromInv(P,"PerksSimHostOrg.HuntingRifleW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M14W");
	RemoveItemFromInv(P,"PerksSimHostOrg.M99W");
	RemoveItemFromInv(P,"PerksSimHostOrg.SCrossbowW");
	RemoveItemFromInv(P,"PerksSimHostOrg.Dual44MagnumW");
	RemoveItemFromInv(P,"PerksSimHostOrg.Magnum44WPistol");
	RemoveItemFromInv(P,"PerksSimHostOrg.WinchesterW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SVDW");

	RemoveItemFromInv(P,"PerksSimHostOrg.AcidGunW");
	RemoveItemFromInv(P,"PerksSimHostOrg.AdrenalineSyringeW");
	RemoveItemFromInv(P,"PerksSimHostOrg.LethalInjectionW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M56W");
	RemoveItemFromInv(P,"PerksSimHostOrg.M7A3MW");
	RemoveItemFromInv(P,"PerksSimHostOrg.MP7MW");
	RemoveItemFromInv(P,"PerksSimHostOrg.MP7M2W");
	RemoveItemFromInv(P,"PerksSimHostOrg.MP5MW");

	RemoveItemFromInv(P,"PerksSimHostOrg.FlameThrowerW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SFlameThrowerW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M79FlameW");
	RemoveItemFromInv(P,"PerksSimHostOrg.MAC10W");
	RemoveItemFromInv(P,"PerksSimHostOrg.HuskGunW");
	RemoveItemFromInv(P,"PerksSimHostOrg.HuskGunClusterW");
	RemoveItemFromInv(P,"PerksSimHostOrg.FireBombW");
	RemoveItemFromInv(P,"PerksSimHostOrg.BomberW");

	RemoveItemFromInv(P,"PerksSimHostOrg.BanHammerW");
	RemoveItemFromInv(P,"PerksSimHostOrg.BigPipeBombW");
	RemoveItemFromInv(P,"PerksSimHostOrg.FFPipeBombW");
	RemoveItemFromInv(P,"PerksSimHostOrg.LAWW");
	RemoveItemFromInv(P,"PerksSimHostOrg.RPGW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M32W");
	RemoveItemFromInv(P,"PerksSimHostOrg.M32ClusterBombW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M79W");
	RemoveItemFromInv(P,"PerksSimHostOrg.PipeBombW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SelfDestructW");
	RemoveItemFromInv(P,"PerksSimHostOrg.VeryBigPipeBombW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M4203W");

	RemoveItemFromInv(P,"PerksSimHostOrg.AK47W");
	RemoveItemFromInv(P,"PerksSimHostOrg.BullpupW");
	RemoveItemFromInv(P,"PerksSimHostOrg.FnFalAW");
	RemoveItemFromInv(P,"PerksSimHostOrg.M41AW");
	RemoveItemFromInv(P,"PerksSimHostOrg.PKM");
	RemoveItemFromInv(P,"PerksSimHostOrg.SCAR17W");
	RemoveItemFromInv(P,"PerksSimHostOrg.SCAR19W");
	RemoveItemFromInv(P,"PerksSimHostOrg.M4W");

	RemoveItemFromInv(P,"PerksSimHostOrg.FireAxeW");
	RemoveItemFromInv(P,"PerksSimHostOrg.AxeW");
	RemoveItemFromInv(P,"PerksSimHostOrg.ChainsawW");
	RemoveItemFromInv(P,"PerksSimHostOrg.KatanaW");
	RemoveItemFromInv(P,"PerksSimHostOrg.MacheteW");
	RemoveItemFromInv(P,"PerksSimHostOrg.RaijinW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SChainsawW");
	RemoveItemFromInv(P,"PerksSimHostOrg.SKatanaW");
	RemoveItemFromInv(P,"PerksSimHostOrg.ClaymoreSwordW");

	RemoveItemFromInv(P,"PerksSimHostOrg.KnifeW");
	RemoveItemFromInv(P,"KFMod.Knife");
	RemoveItemFromInv(P,"PerksSimHostOrg.SingleW");
	RemoveItemFromInv(P,"KFMod.Single");
}

function GiveItemToEnemySupportSpec(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.AA12W");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.AFS12W");
	}
	else if(botLevel==4)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.SBoomStickW");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToEnemySupportSpec error");
	}
}

function GiveItemToEnemyBerserker(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");	
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.KatanaW");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.FireAxeW");
	}
	else if(botLevel==4)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.SChainsawW");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToEnemyBerserker error");
	}
}

function GiveItemToEnemyCommando(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.ThompsonSubmachineGun");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M249");
	}
	else if(botLevel==4)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M249Ex");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToEnemyCommando error");
	}
}

function GiveItemToEnemyFieldMedic(int botLevel)
{
	Pawn.GiveWeapon("PerksSimHostOrg.MK23W");
}

function GiveItemToEnemyFirebug(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MAC10W");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M79FlameW");
	}
	else if(botLevel==4)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.BomberW");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToEnemyFirebug error");
	}
}

function GiveItemToEnemySharpshooter(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.DualDeagleW");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M14W");
	}
	else if(botLevel==4)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M99W");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToEnemySharpshooter error");
	}
}

function GiveItemToEnemyDemolitions(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M79W");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.M32ClusterBombW");
	}
	else if(botLevel==4)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.LAWW");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToEnemyDemolitions error");
	}
}


function GiveItemToAllySupportSpec(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MacheteW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.AA12W");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.AFS12W");
	}
	else if(botLevel==4)
	{
		Pawn.Health=150;
		Pawn.GiveWeapon("PerksSimHostOrg.PatGun");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToAllySupportSpec error");
	}
}

function GiveItemToAllyBerserker(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.AxeW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.KatanaW");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.SChainsawW");
	}
	else if(botLevel==4)
	{
		Pawn.Health=150;
		Pawn.GiveWeapon("PerksSimHostOrg.PatGun");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToAllyBerserker error");
	}
}

function GiveItemToAllyCommando(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MK23W");
		Pawn.GiveWeapon("KFMod.Knife");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.AK47SHAssaultRifle");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.PKM");
	}
	else if(botLevel==4)
	{
		Pawn.Health=150;
		Pawn.GiveWeapon("PerksSimHostOrg.PatGun");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToAllyCommando error");
	}
}

function GiveItemToAllyFieldMedic(int botLevel)
{
	Pawn.Health=150;
	Pawn.GiveWeapon("PerksSimHostOrg.M7A3MW");
}

function GiveItemToAllyFirebug(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MAC10W");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MAC10W");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.HuskGunClusterW");
	}
	else if(botLevel==4)
	{
		Pawn.Health=150;
		Pawn.GiveWeapon("PerksSimHostOrg.PatGun");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToAllyFirebug error");
	}
}

function GiveItemToAllySharpshooter(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.DualDeagleW");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.CrossbowW");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.HuntingRifleW");
	}
	else if(botLevel==4)
	{
		Pawn.Health=150;
		Pawn.GiveWeapon("PerksSimHostOrg.PatGun");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToAllySharpshooter error");
	}
}

function GiveItemToAllyDemolitions(int botLevel)
{
	if(botLevel==1)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.MK23W");
		Pawn.GiveWeapon("KFMod.Knife");
	}
	else if(botLevel==2)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.LAWW");
	}
	else if(botLevel==3)
	{
		Pawn.GiveWeapon("PerksSimHostOrg.LAWW");
	}
	else if(botLevel==4)
	{
		Pawn.Health=150;
		Pawn.GiveWeapon("PerksSimHostOrg.PatGun");
	}
	else
	{
		Pawn.GiveWeapon("KFMod.Knife");
		Log("GiveItemToAllyDemolitions error");
	}
}

defaultproperties
{
}
